package com.lzx.adx.report.support.strategy.v3.media;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ReflectUtil;
import com.alibaba.fastjson.JSON;
import com.lzs.adx.commmon.constant.RedisCacheKey;
import com.lzs.adx.commmon.enums.ReportEnums;
import com.lzs.adx.commmon.utils.DateUtils;
import com.lzs.adx.commmon.utils.SpringContextUtils;
import com.lzx.adx.report.constant.StatusConstant;
import com.lzx.adx.report.dto.*;
import com.lzx.adx.report.service.*;
import com.lzx.adx.report.util.AdPerUtil;
import com.lzx.adx.report.util.DynamicRequestLimiter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.ResponseEntity;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
public abstract class AbstractChannel {

    /**
     * 通用的可回传功能
     * @param per
     * @return
     */
    public  boolean shouldIdentifyAd(Double per) {
        Random random = new Random();
        double randomValue = random.nextDouble(); // 生成到1之间的随机数
        log.info("随机数为{}", randomValue);
        return randomValue > per;
    }




    public boolean base(ReportDTO reportDTO, OcpxAccountDTO ocpxAccountDTO, String callType, String time) {
        ReportService reportService = SpringContextUtils.getBean(ReportService.class);
        Map<String, CallTypeMappingDTO> collect = getCallTypeMap(ocpxAccountDTO);
        DynamicRequestLimiter dynamicRequestLimiter=SpringContextUtils.getBean(DynamicRequestLimiter.class);

        //2.从缓存加载配置
        reportDTO.setResultType(callType);
        reportDTO.setResultTime(time);
        reportDTO.setUpdateTime(new Date());
        reportService.updateData(reportDTO,callType,2);


        CallTypeMappingDTO callTypeMappingDTO = collect.get(callType);
        String requestId = reportDTO.getBizRequestId();

        //检查总转化量控制的限制
        if (checkTotalLimit(ocpxAccountDTO, callType,  requestId)){
            return false;
        }
        //检查总当日转化量控制的限制
        if (checkCurrentDayLimit(ocpxAccountDTO, callType,  requestId)){
            return false;
        }

        if (!collect.containsKey(callType)){
            log.info("账户{}接收了产品段的回调信息当前流水号：{}，事件类型{}不合法，不做数据回传",ocpxAccountDTO.getId(), requestId,callType);
            return false;
        }

        String date = DateUtils.format(new Date(), "yyyyMMdd");
        String account_count_key=String.format(RedisCacheKey.account_count_key, reportDTO.getDspId(),date);
        String account_processed_key=String.format(RedisCacheKey.account_processed_key, reportDTO.getDspId(),date);


        Double per = ocpxAccountDTO.getPer();
        if (Objects.nonNull(per)) {
            String type = getType(callType, ocpxAccountDTO.getProductChannel());
            if(StringUtils.isNotBlank(type)){
                String key = com.lzx.adx.report.enums.ReportEnums.getKey(type);
                Object fieldValue = ReflectUtil.getFieldValue(ocpxAccountDTO, key + "Per");
                 if(Objects.nonNull(fieldValue) && shouldIdentifyAd(Double.valueOf(fieldValue.toString()))){
                     log.info("账户{}流水号{}超出了比例,不做回传", reportDTO.getDspId(), reportDTO.getBizRequestId());
                     return false;
                 }else if (shouldIdentifyAd(per)) {
                    log.info("账户{}流水号{}超出了比例,不做回传", reportDTO.getDspId(), reportDTO.getBizRequestId());
                    return false;
                 }
            }else{
                if (shouldIdentifyAd(per)) {
                    log.info("账户{}流水号{}超出了比例,不做回传", reportDTO.getDspId(), reportDTO.getBizRequestId());
                    return false;
                }
            }
        }
        return true;
    }

    public  Map<String, CallTypeMappingDTO> getCallTypeMap(OcpxAccountDTO ocpxAccountDTO) {
        List<CallTypeMappingDTO> callTypeMappingDTOS = JSON.parseArray(ocpxAccountDTO.getTypeList(), CallTypeMappingDTO.class);

        Map<String, CallTypeMappingDTO> collect = callTypeMappingDTOS.stream().collect(Collectors.toMap(CallTypeMappingDTO::getProductReturnType, Function.identity()));
        return collect;
    }

    /**
     * 检查总转化量控制的限制
     * @param ocpxAccountDTO
     * @param callType

     * @param requestId
     * @return
     */
    private static boolean checkTotalLimit(OcpxAccountDTO ocpxAccountDTO, String callType,  String requestId) {
        BackDataService backDataService = SpringContextUtils.getBean(BackDataService.class);
        ResultTypeService resultTypeService = SpringContextUtils.getBean(ResultTypeService.class);
        OcpxAccountService ocpxAccountService = SpringContextUtils.getBean(OcpxAccountService.class);
        if(Objects.nonNull(ocpxAccountDTO.getTotalLimitNumber()) && ocpxAccountDTO.getTotalLimitNumber()>0){
            Map<String,Object> params = new HashMap<>();
            params.put("productChannle", ocpxAccountDTO.getProductChannel());
            params.put("resultType", callType);
            List<ResultTypeDTO> list = resultTypeService.list(params);
            if(CollectionUtil.isEmpty(list)){
                log.error("账户号{},未配置转化类型{}", ocpxAccountDTO.getId(), callType);
            }else{
                ResultTypeDTO resultTypeDTO = list.get(0);
                if(ocpxAccountDTO.getKeyType().equals(ReportEnums.getKey(resultTypeDTO.getType()))){
                    long total = backDataService.countTotal(ocpxAccountDTO.getId(), callType);
                    if(total>= ocpxAccountDTO.getTotalLimitNumber()){
                        log.info("账户{}流水号{}超出了转化总量限制，不做回传,转化类型{}", ocpxAccountDTO.getId(), requestId, callType);
                        //更新账户的状态
                        ocpxAccountDTO.setStatus(StatusConstant.DISABLE);
                        ocpxAccountService.update(ocpxAccountDTO);
                        //更新缓存
                        ocpxAccountService.sysnCacheToDb();
                        return true;
                    }
                }else{
                    log.info("账户号{},转化类型{}，非关键指标，不做限制处理");
                }
            }
        }
        return false;
    }


    public String getType(String callType,String productChannel){
        ResultTypeService resultTypeService = SpringContextUtils.getBean(ResultTypeService.class);
        Map<String,Object> params = new HashMap<>();
        params.put("productChannle", productChannel);
        params.put("resultType", callType);
        List<ResultTypeDTO> list = resultTypeService.list(params);
        if(CollectionUtil.isNotEmpty(list)){
            return list.get(0).getType();
        }
        return null;
    }


    /**
     * 检查总转化量控制的限制
     * @param ocpxAccountDTO
     * @param callType
     * @param requestId
     * @return
     */
    private static boolean checkCurrentDayLimit(OcpxAccountDTO ocpxAccountDTO, String callType,  String requestId) {
        BackDataService backDataService = SpringContextUtils.getBean(BackDataService.class);
        ResultTypeService resultTypeService = SpringContextUtils.getBean(ResultTypeService.class);
        OcpxAccountService accountService = SpringContextUtils.getBean(OcpxAccountService.class);
        if(Objects.nonNull(ocpxAccountDTO.getDayLimitNumber()) && ocpxAccountDTO.getDayLimitNumber()>0){
            Map<String,Object> params = new HashMap<>();
            params.put("productChannle", ocpxAccountDTO.getProductChannel());
            params.put("resultType", callType);
            List<ResultTypeDTO> list = resultTypeService.list(params);
            if(CollectionUtil.isEmpty(list)){
                log.error("账户号{},未配置转化类型{}", ocpxAccountDTO.getId(), callType);
            }else{
                ResultTypeDTO resultTypeDTO = list.get(0);
                if(ocpxAccountDTO.getKeyType().equals(ReportEnums.getKey(resultTypeDTO.getType()))){
                    long total = backDataService.countCurrentDayTotal(ocpxAccountDTO.getId(), callType, DateUtils.getCurrentTime());
                    if(total>= ocpxAccountDTO.getDayLimitNumber()){
                        log.info("账户{}流水号{}超出了当日转化总量限制，不做回传,转化类型{}", ocpxAccountDTO.getId(), requestId, callType);
                         if(!ocpxAccountDTO.getStatus().equals(StatusConstant.NUMBER_LIMITER)){
                             //更新账户的状态
                             ocpxAccountDTO.setStatus(StatusConstant.NUMBER_LIMITER);
                             accountService.update(ocpxAccountDTO);
                             //更新缓存
                             accountService.sysnCacheToDb();
                         }
                         return true;
                    }
                }else{
                    log.info("账户号{},转化类型{}，非关键指标，不做限制处理");
                }
            }
        }
        return false;
    }


    public abstract ResponseEntity callback(ReportDTO reportDTO, OcpxAccountDTO accountDTO,String callType,String ts);

}
